/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package meteocal.business.control;

import java.security.Principal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;
import meteocal.business.boundary.BadWeatherFacade;
import meteocal.business.boundary.EventFacade;
import meteocal.business.boundary.NotificationFacade;
import meteocal.business.entity.Event;
import meteocal.business.entity.Notification;
import meteocal.business.entity.Weather;
import meteocal.business.security.boundary.UserManager;

/**
 *
 * @author luana
 */
@Stateless
public class ForecastChecker {
    
    
    private static final Logger logger = Logger.getLogger(EventFacade.class.getName());
    
    @EJB
    BadWeatherFacade bw;
    
    @EJB
    EventFacade ef;
    
    @EJB 
    NotificationFacade nf; 
    
    @EJB 
    UserManager um; 
        
    @Inject
    Principal principal;
    
    DateUtils du; 

    public ForecastChecker(){
        du = new DateUtils();
    }
    
    /**
     * This method  checks if bad weather is expected, and in 
     * this case a new notification is generated.
     * Note: only outdoor events has defined "bad weathers".
     * @param event 
     * @return true if bad weather is expected, false otherwise.
     */
    public boolean checkForecast(Event event){
        
        Weather expected_weather = event.getExpectedWeather();
        String category = expected_weather.getCategory();
        
        if (bw.findInBad(event, category).isEmpty()){
            return false;
           
        } else {
            return true;
        }
      
    }
    
    public void checkEvent(){
        
        Date today = du.todayMidnight();
        
        
        // Look for the events the user creates
        List<Event> createdEvents = ef.searchEventOfUser(principal.getName());
        // Look for events the user will partecipat
        List<Event> partecipatingEvents = ef.searchInParticipants(principal.getName());
        
        for (Event createdEvent : createdEvents) {
            Date dateC = createdEvent.getStarting_date();
            Date timeC = createdEvent.getStartingTime();
            // I need to merge them
            Date dateMergedC = du.singleDate(dateC, timeC);
            // I only consider outdoor events
            if (createdEvent.getType()) {
                // I don't consider past events
                if (dateC.after(today)) {
                    long diff = du.getDateDiff(today, dateMergedC, TimeUnit.DAYS);
                    if (diff < 4 && diff > 1) {
                       if (checkForecast(createdEvent)) {
                            tryRescheduling(createdEvent);
                        }

                    } else {
                        if (diff == 1) {
                            if(checkForecast(createdEvent)){
                              // Notifies the bad weather
                              nf.create(createdEvent,principal.getName(),4);
                            }
                        }   
                    }
                }
            }
            
        }

           
        for (Event partecipatingEvent : partecipatingEvents) {
            Date dateP = partecipatingEvent.getStarting_date();
            Date timeP = partecipatingEvent.getStartingTime();
            // I need to merge them
            Date dateMergedP = du.singleDate(dateP, timeP);
            // I only consider outdoor events
            if (partecipatingEvent.getType()) {
                // I don't consider past events 
                if (dateMergedP.after(today)) {
                    long diff2 = du.getDateDiff(today, dateMergedP, TimeUnit.DAYS);
                    if (diff2 == 1) {
                        if (checkForecast(partecipatingEvent)) {
                            nf.create(partecipatingEvent,principal.getName(),4);
                        }
                    }
                }
            }

        }

  
      
    }
    
    /**
     * Tries to move the event to the closest day with a good forecast. 
     * Note that I can have info on the weather only for the next 5 days; 
     * @param e - Event 
     */
    public void tryRescheduling(Event e){
        
        WeatherChecker wc = new WeatherChecker();
        Date today = du.currentDay();
        
        int max_days = 6; 
        
        for(int i = 0; i<max_days;i++){
           Date newDate = du.addDays(today, i);
           Weather w = wc.checkWeather(e.getPlace(), newDate, e.getStartingTime());
           if(!isBad(e,w)){
              //Generates a new rescheduling proposition
              nf.createRescheduling(e, e.getCreator().getUsername(), 5, newDate);
              return; 
           }
        }
        
    }
    
    /**
     * Says of a given event and weather if this weather is to be considered bad for the event. 
     * @param e
     * @param w
     * @return true if w is a bad weather for the event e
     */
    public boolean isBad(Event e, Weather w){
        
        if (bw.findInBad(e, w.getCategory()).isEmpty()){
            return false;
           
        } else {
            return true;
        }
        
    }
    
}
